/*
 * Copyright (C) 2011 Michael Widmer <widmm8@bfh.ch>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package ch.bfh.aeneas.navigation.app;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.location.Location;
import android.os.Bundle;
import android.os.IBinder;
import android.os.PowerManager;
import android.preference.PreferenceManager;
import android.util.Log;
import ch.bfh.aeneas.R;
import ch.bfh.aeneas.exchange.intent.AeneasIntent;
import ch.bfh.aeneas.core.io.gesture.GestureActivity;
import ch.bfh.aeneas.core.location.PositionManager;
import ch.bfh.aeneas.core.location.PositionManager.OnPositionChangedListener;
import ch.bfh.aeneas.core.location.PositionManager.PositionManagerBinder;
import ch.bfh.aeneas.navigation.app.NavigationService.OnResultsListener;
import ch.bfh.aeneas.navigation.app.NavigationService.OnStateListener;
import java.util.ArrayList;
import java.util.List;

/**
 * This is the base class for most of the navigation activities. It provides 
 * functionality to automatically getting the current position, acquiring a
 * WakeLock and offers diverse listeners.
 * 
 * It starts to gather a position fix as soon as it gets resumed.
 * @author Michael Widmer <widmm8@bfh.ch>
 */
public abstract class NavigationActivity extends GestureActivity {

    //TODO:
    //onRetainNonConfigurationInstance
    //getLastNonConfigurationInstance
    
    protected ServiceConnection mPositionConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName arg0, IBinder arg1) {
            mPosManager = (PositionManager) ((PositionManagerBinder) arg1).getService();
            mPositionStarted = true;
            onPositionConnected();
        }

        public void onServiceDisconnected(ComponentName arg0) {
            mPositionStarted = false;
            onPositionDisconnect();
        }        
    };
    
    protected OnResultsListener mResultsListener = new OnResultsListener() {
        public void onResults(int request, Intent i) {
            Log.i(LOG_TAG, "Received answer from service!");
            onResultReceived(request, i);
        }

        public void onRequestClosed(int request) {
            onRequestFinished(request);
        }

        public void onRequestSent(int request) {
            onRequestStarted(request);
        }
    };
    
    protected OnStateListener mStateListener = new OnStateListener() {

        public void onBeforeInit() {
            onStateBeforeInit();
        }

        public void onAfterInit() {
            onStateAfterInit();
        }

        public void onReady() {
            onStateReady();
        }        
    };
            
    private OnPositionChangedListener mChangeListener = new OnPositionChangedListener() {
        public void onPositionChanged(Location l) {
            //Log.i(LOG_TAG, "Received new Location: "+l.getLatitude()+"/"+l.getLongitude());
            mLastLocation = l;
            onPositionReceived(l);
        }

        public void onPositionFix(Location l) {
            onFirstPosition(l);
        }
    };
    
    private static final String LOG_TAG = "NavigationActivity";
    
    protected Location mLastLocation;
    protected PositionManager mPosManager;
    protected List<Intent> mAnswers;
    private boolean mPositionStarted;
    private boolean mFixing;
    private PowerManager mPowerManager;
    private PowerManager.WakeLock mWakeLock;
    
    @Override
    /**
     * {@inheritDoc}
     */
    public void onCreate(Bundle icicle, int resId) {
        super.onCreate(icicle, resId);
        
        mPositionStarted = false;
        mFixing = false;
        
        mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
        mWakeLock = mPowerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "AeneasNavigation");
    }
    
    @Override
    /**
     * {@inheritDoc}
     */
    public void onResume() {
        super.onResume();
        
        bindService(new Intent(this, PositionManager.class),mPositionConnection,Context.BIND_AUTO_CREATE);
    }
    
    @Override
    /**
     * {@inheritDoc}
     */
    public void onPause() {
        super.onPause();
        stopListening();
        
        if(mPositionStarted) {
            unbindService(mPositionConnection);
        }
    }
    
    @Override
    /**
     * {@inheritDoc}
     */
    public void onDestroy() {
        super.onDestroy();
    }
    
    private void onFirstPosition(Location l) {
        mFixing = true;
        onPositionReceivedFirst(l);
    }
    
    /**
     * Returns the SharedPreferences for the whole application.
     * @return 
     */
    protected final SharedPreferences getApplicationPreferences() {
        return PreferenceManager.getDefaultSharedPreferences(super.getApplicationContext());
    }
    
    /**
     * Returns a boolean value that indicates if activity is currently getting
     * valid updates from PositionManager (true) or not (false).
     * @return 
     */
    protected final boolean isPositionFixing() {
        return mFixing;
    }
    
    /**
     * Returns a boolean value that indicates if the connection to 
     * PositionManager has already been established (true) or not (false).
     * @return 
     */
    protected final boolean isPositionManagerReady() {
        return mPositionStarted;
    }
    
    protected void acquireWakeLock() {
        mWakeLock.acquire();
    }
    
    protected void releaseWakeLock() {
        mWakeLock.release();
    }
    
    /**
     * Makes the activity to add a listener to PositionManager and causing it
     * to start looking for position fixes.
     */
    protected final void startListening() {
        mPosManager.addOnLocationChangedListener(mChangeListener);
        onPositionStartListen();
    }
    
    /**
     * Makes the activity to remove the listener from PositionManager. The
     * activity will no longer receive updates on current position.
     */
    protected final void stopListening() {
        if(mPositionStarted) {
            mPosManager.removeOnLocationChangedListener(mChangeListener);
            mFixing = false;
        }
        onPositionStopListen();
    }
    
    /**
     * Tells the text-to-speech-engine to say the text after it got proceeded by
     * a language recognition filter that switches language for output.
     * @param inText The text to be spoken
     */
    public void speechAiOn(String inText) {
        speech(inText, true);
    }    
    
    /**
     * Tells the text-to-speech-engine to say the text exactly as passed.
     * @param inText The text to be spoken
     */
    public void speech(String inText) {
        this.speech(inText, false);
    }
    
    private void speech(String inText, boolean useAi) {
        /*Intent output = new Intent(AeneasIntent.ACTION_OUTPUT);
        output.putExtra("speech", inText);
        output.putExtra("useAi", useAi);*/
        super.sendBroadcast(AeneasIntent.getOutputIntent(inText, useAi));
    }
    
    /**
     * Gets called when the connection to PositionManager gets closed.
     * @see #stopListening()
     * @see PositionManager
     */
    protected void onPositionDisconnect() {};
    /**
     * Gets called when the connection to PositionManager gets closed.
     * @see #startListening()
     * @see PositionManager
     */
    protected void onPositionConnected() {};
    /**
     * Gets called when the activity receives the very first position-fix from
     * PositionManager.
     * @see #startListening()
     * @see PositionManager
     * @param l The position-fix received from PositionManager
     */
    protected void onPositionReceivedFirst(Location l) {};
    /**
     * Gets called when the activity receives a position-fix other than the
     * first one from PositionManager.
     * @see #startListening()
     * @see PositionManager
     * @param l The position-fix received from PositionManager
     */
    protected void onPositionReceived(Location l) {};
    /**
     * Gets called when the activity starts to listen for updates.
     * @see #startListening()
     * @see PositionManager
     */
    protected void onPositionStartListen() {};
    /**
     * Gets called when the activity stops listening for updates from 
     * PositonManager.
     * @see #startListening()
     * @see PositionManager
     */
    protected void onPositionStopListen() {};
    
    /**
     * Gets called everytime the activity receives an answer from one of its 
     * services, after a request had been sent.
     * 
     * @param request The id of the request
     * @param i The data past with this answer
     * @see #onRequestStarted(int) 
     * @see NavigationService
     */
    protected void onResultReceived(int request, Intent i) {
        try {
            mAnswers.add(i);
        } catch(Exception ex) {
            Log.i(LOG_TAG, "Error while adding answer: "+ex.getMessage());
        }
    }
    
    /**
     * Gets called as soon as the activity starts a request on one of its 
     * services.
     * @param request The id of the request
     */
    protected void onRequestStarted(int request) {
        speech(getString(R.string.state_request_started));
        mAnswers = new ArrayList<Intent>();
    };
    
    /**
     * Gets called as soon as a request started by the activity finished.
     * @param request The id of the request
     */
    protected void onRequestFinished(int request) {
        speech(getString(R.string.state_request_finished));
    };
    
    
    protected void onStateBeforeInit() {};
    protected void onStateAfterInit() {};
    
    /**
     * Gets called, when the object the listener is registered on, dispatches
     * the corresponding event. 
     */
    protected void onStateReady() {};
}
